<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>
  </body>
  
  <script>
    /*prototype & __proto__*/
    function Func() {
    }
    
    console.log(Func.prototype);//{constructor: ƒ}
    console.log(new Func().__proto__);//{constructor: ƒ}
    console.log(Object.getPrototypeOf(new Func()));//{constructor: ƒ}
    console.log(Func.prototype === new Func().__proto__);//true
    console.log(Func.prototype === Object.getPrototypeOf(new Func()));//true
    console.log(new Func().__proto__ === Object.getPrototypeOf(new Func()));//true
    
    /*原型继承的核心是将子类的原型对象设置为父类的实例对象*/
    // 1.定义父类
    function PrototypeInheritParent() {
      this.parent = 'Parent';
    }
    
    PrototypeInheritParent.prototype.showParent = function () {
      console.log(this.parent);
    };
    
    // 2.定义子类
    function PrototypeInheritSon() {
      this.son = 'Son';
    }
    
    // 3.创建父类对象赋值给子类原型**
    PrototypeInheritSon.prototype = new PrototypeInheritParent();
    
    let prototypeInheritSon = new PrototypeInheritSon();
    console.log(prototypeInheritSon.parent);//Parent
    prototypeInheritSon.showParent();//Parent
    console.log(prototypeInheritSon.son);//Son
    
    /*原型链上溯*/
    /*①JS中每个类都存在显示原型`prototype`，在显示原型`prototype`上添加属性*/
    function PrototypeInheritProcess() {
    }
    
    console.log(PrototypeInheritProcess.prototype);
    /*{
        constructor: ƒ PrototypeInheritProcess(),

        [[Prototype]]: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }*/
    PrototypeInheritProcess.prototype.prototypeAttr = 'prototypeAttr';
    console.log(PrototypeInheritProcess.prototype);
    /*{
        prototypeAttr: "prototypeAttr",
        constructor: ƒ PrototypeInheritProcess(),

        [[Prototype]]: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
        }*/
    /*②JS中每个对象都存在隐式原型`__proto__`，创建对象实例后在隐式原型`__proto__`上添加属性*/
    let prototypeInheritProcess = new PrototypeInheritProcess();
    prototypeInheritProcess.instanceAttr = 'instanceAttr'
    console.log(prototypeInheritProcess);
    /*{
        instanceAttr: "instanceAttr",

        [[Prototype]]: {
          prototypeAttr: "prototypeAttr",
          constructor: ƒ PrototypeInheritProcess(),

          [[Prototype]]: {
              constructor: ƒ Object(),
              hasOwnProperty: ƒ hasOwnProperty(),
              isPrototypeOf: ƒ isPrototypeOf(),
              propertyIsEnumerable: ƒ propertyIsEnumerable(),
              toLocaleString: ƒ toLocaleString(),
              toString: ƒ toString(),
              valueOf: ƒ valueOf()
          }
        }
    }*/
    console.log(prototypeInheritProcess.__proto__ === PrototypeInheritProcess.prototype);//true
    /*③访问对象`prototypeInheritProcess`的某成员时首先在该对象中寻找该成员，未找到则在该对象的对象原型`prototypeInheritProcess.__proto__`或`PrototypeInheritProcess.prototype`中寻找，仍未找到则在该对象的对象原型的对象原型`prototypeInheritProcess.__proto__.__proto__`或`PrototypeInheritProcess.prototype.prototype`中寻找，直到window.Object.prototype内都未找到则返回undefined*/
    console.log(prototypeInheritProcess.instanceAttr);//instanceAttr
    console.log(prototypeInheritProcess.prototypeAttr);//prototypeAttr
    console.log(prototypeInheritProcess.__proto__.instanceAttr);//undefined
    console.log(prototypeInheritProcess.__proto__.prototypeAttr);//prototypeAttr
    console.log(PrototypeInheritProcess.prototype.instanceAttr);//undefined
    console.log(PrototypeInheritProcess.prototype.prototypeAttr);//prototypeAttr
    console.log(prototypeInheritProcess.__proto__ === PrototypeInheritProcess.prototype);//true
    
    /*原型继承说明：常量属性和方法通常被设置于对象原型中，例如创建1000个对象时对象原型只占1份空间，利于节省空间且避免全局作用域污染*/
    
    
    /*Object的`create()`方法将参数作为新创建对象的对象原型*/
    function ObjectCreate() {
      this.name = 'ObjectCreate'
    }
    
    let objectCreate = Object.create(new ObjectCreate());
    console.log(objectCreate);//ObjectCreate {}
    console.log(objectCreate instanceof Object);//true
    console.log(objectCreate.__proto__);//ObjectCreate {name: 'ObjectCreate'}
    console.log(objectCreate.__proto__ instanceof ObjectCreate);//true
    
    /*存在于对象原型中的构造属性constructor指构造函数，通过`new 原型.constructor()`的形式可以创建对象实例，constructor的name属性表示构造器的名称*/
    function Constructor(name) {
      this.name = name
    }
    
    console.log(Constructor.prototype.constructor.name);//Constructor
    console.log(new Constructor.prototype.constructor('syx'));//Constructor {name: 'syx'}
    
    /*第一次read该属性时该对象内不存在则沿着原型链向上寻找，第二次write该属性时该对象内不存在则在该对象内创建该属性并赋值，第三次read该属性时该对象内已存在②内创建的该属性则直接读取*/
    function ReadWriteRead() { }
    
    ReadWriteRead.prototype.name = 'prototypeArr';
    
    let readWriteRead = new ReadWriteRead();
    console.log(readWriteRead.name);//prototypeArr
    console.log(readWriteRead);//ReadWriteRead {}
    
    readWriteRead.name = 'readWriteReadArr';
    console.log(readWriteRead.name);//readWriteReadArr
    console.log(readWriteRead);//ReadWriteRead {name: 'readWriteReadArr'}
  </script>
</html>